package com.beiju.template.utils;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.ConstVal;
import com.baomidou.mybatisplus.generator.config.FileOutConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.FileType;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import lombok.extern.slf4j.Slf4j;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * @version v1.0
 * @ClassName: Template.java
 * @Description: TODO(一句话描述该类的功能)
 * @Author: BeiJu
 * @Date: 2021/1/13 13:32
 */
@Slf4j
public class MyTemplate extends AbstractTemplateEngine {
	private static final String DOT_VM = ".vm";
	private VelocityEngine velocityEngine;

	@Override
	public MyTemplate init(ConfigBuilder configBuilder) {
		super.init(configBuilder);
		if (null == velocityEngine) {
			Properties p = new Properties();
			p.setProperty(ConstVal.VM_LOAD_PATH_KEY, ConstVal.VM_LOAD_PATH_VALUE);
			p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, StringPool.EMPTY);
			p.setProperty(Velocity.ENCODING_DEFAULT, ConstVal.UTF8);
			p.setProperty(Velocity.INPUT_ENCODING, ConstVal.UTF8);
			p.setProperty("file.resource.loader.unicode", StringPool.TRUE);
			velocityEngine = new VelocityEngine(p);
		}
		return this;
	}
	/**
	 * 将模板转化成为文件
	 *
	 * @param objectMap    渲染对象 MAP 信息
	 * @param templatePath 模板文件
	 * @param outputFile   文件生成的目录
	 */
	@Override
	public void writer(Map<String, Object> objectMap, String templatePath, String outputFile) throws Exception {
		Template template = velocityEngine.getTemplate(templatePath, ConstVal.UTF8);
		try (FileOutputStream fos = new FileOutputStream(outputFile);
			 OutputStreamWriter ow = new OutputStreamWriter(fos, ConstVal.UTF8);
			 BufferedWriter writer = new BufferedWriter(ow)) {
			template.merge(new VelocityContext(objectMap), writer);
		}
		log.info("模板:{};  文件:{}" ,templatePath,outputFile);
	}

	/**
	 * 模板真实文件路径
	 *
	 * @param filePath 文件路径
	 * @return ignore
	 */
	@Override
	public String templateFilePath(String filePath) {
		if (null == filePath || filePath.contains(DOT_VM)) {
			return filePath;
		}
		return filePath + DOT_VM;
	}
	/**
	 * 输出 java xml 文件
	 */
	@Override
	public AbstractTemplateEngine batchOutput() {
		//配置信息
		ConfigBuilder configBuilder = getConfigBuilder();
		Map<String, String> packageInfo = configBuilder.getPackageInfo();
    	System.out.println(packageInfo);
		try {
			List<TableInfo> tableInfoList = getConfigBuilder().getTableInfoList();
			for (TableInfo tableInfo : tableInfoList) {
        		System.out.println(tableInfo);
				Map<String, Object> objectMap = getObjectMap(tableInfo);
				Map<String, String> pathInfo = getConfigBuilder().getPathInfo();
				TemplateConfig template = getConfigBuilder().getTemplate();

				//实体类包名
				objectMap.put("entityPackageName",packageInfo.get("Entity"));
				//service类包名
				objectMap.put("servicePackageName",packageInfo.get("Service"));
				//service实现类包名
				objectMap.put("serviceImplPackageName",packageInfo.get("ServiceImpl"));

				//mapper类包名
				objectMap.put("mapperPackageName",packageInfo.get("Mapper"));
				//controller类包名
				objectMap.put("controllerPackageName",packageInfo.get("Controller"));
				//控制类名
				objectMap.put("ControllerName",tableInfo.getControllerName());
				//实体类注释
				objectMap.put("comment",tableInfo.getComment());
				//service名称
				objectMap.put("ServiceName",tableInfo.getServiceName());
				//service对象名称
				objectMap.put("serviceName",StrUtil.removePreAndLowerFirst(tableInfo.getServiceName(),"I"));
				//service实现名称
				objectMap.put("ServiceImplName",tableInfo.getServiceImplName());
				//mapper名称
				objectMap.put("XmlName",tableInfo.getXmlName());
				//mapper对象名称
				objectMap.put("xmlName",StrUtil.lowerFirst(tableInfo.getXmlName()));
				//实体类名称
				objectMap.put("ClassName",tableInfo.getEntityName());
				//实体类对象名称
				objectMap.put("className",StrUtil.lowerFirst(tableInfo.getEntityName()));
				//mapper类名
				objectMap.put("MapperName",tableInfo.getMapperName());
				//mapper类对象名
				objectMap.put("mapperName",StrUtil.lowerFirst(tableInfo.getMapperName()));

				//实体类字段
				objectMap.put("columns",tableInfo.getFields());

				// 自定义内容
				InjectionConfig injectionConfig = getConfigBuilder().getInjectionConfig();
				if (null != injectionConfig) {
					injectionConfig.initTableMap(tableInfo);
					objectMap.put("cfg", injectionConfig.getMap());
					List<FileOutConfig> focList = injectionConfig.getFileOutConfigList();
					if (CollectionUtils.isNotEmpty(focList)) {
						for (FileOutConfig foc : focList) {
							if (isCreate(FileType.OTHER, foc.outputFile(tableInfo))) {
								writerFile(objectMap, foc.getTemplatePath(), foc.outputFile(tableInfo));
							}
						}
					}
				}

				// Mp.java
				String entityName = tableInfo.getEntityName();
				if (null != entityName && null != pathInfo.get(ConstVal.ENTITY_PATH)) {
					String entityFile = String.format((pathInfo.get(ConstVal.ENTITY_PATH) + File.separator + "%s" + suffixJavaOrKt()), entityName);
					if (isCreate(FileType.ENTITY, entityFile)) {
						writerFile(objectMap, templateFilePath(template.getEntity(getConfigBuilder().getGlobalConfig().isKotlin())), entityFile);
					}
				}
				// MpMapper.java
				if (null != tableInfo.getMapperName() && null != pathInfo.get(ConstVal.MAPPER_PATH)) {
					String mapperFile = String.format((pathInfo.get(ConstVal.MAPPER_PATH) + File.separator + tableInfo.getMapperName() + suffixJavaOrKt()), entityName);
					if (isCreate(FileType.MAPPER, mapperFile)) {
						writerFile(objectMap, templateFilePath(template.getMapper()), mapperFile);
					}
				}
				// MpMapper.xml
				if (null != tableInfo.getXmlName() && null != pathInfo.get(ConstVal.XML_PATH)) {
					String xmlFile = String.format((pathInfo.get(ConstVal.XML_PATH) + File.separator + tableInfo.getXmlName() + ConstVal.XML_SUFFIX), entityName);
          			System.out.println("xml路径："+xmlFile);
					if (isCreate(FileType.XML, xmlFile)) {
						writerFile(objectMap, templateFilePath(template.getXml()), xmlFile);
					}
				}
				// IMpService.java
				if (null != tableInfo.getServiceName() && null != pathInfo.get(ConstVal.SERVICE_PATH)) {
					String serviceFile = String.format((pathInfo.get(ConstVal.SERVICE_PATH) + File.separator + tableInfo.getServiceName() + suffixJavaOrKt()), entityName);
					if (isCreate(FileType.SERVICE, serviceFile)) {
						writerFile(objectMap, templateFilePath(template.getService()), serviceFile);
					}
				}
				// MpServiceImpl.java
				if (null != tableInfo.getServiceImplName() && null != pathInfo.get(ConstVal.SERVICE_IMPL_PATH)) {
					String implFile = String.format((pathInfo.get(ConstVal.SERVICE_IMPL_PATH) + File.separator + tableInfo.getServiceImplName() + suffixJavaOrKt()), entityName);
					if (isCreate(FileType.SERVICE_IMPL, implFile)) {
						writerFile(objectMap, templateFilePath(template.getServiceImpl()), implFile);
					}
				}
				// MpController.java
				if (null != tableInfo.getControllerName() && null != pathInfo.get(ConstVal.CONTROLLER_PATH)) {
					String controllerFile = String.format((pathInfo.get(ConstVal.CONTROLLER_PATH) + File.separator + tableInfo.getControllerName() + suffixJavaOrKt()), entityName);
					if (isCreate(FileType.CONTROLLER, controllerFile)) {
						writerFile(objectMap, templateFilePath(template.getController()), controllerFile);
					}
				}
			}
		} catch (Exception e) {
			logger.error("无法创建文件，请检查配置信息！", e);
		}
		return this;
	}


}